#include "../include/muduo/proto/codec.h"
#include "../include/muduo/proto/dispatcher.h"
#include "../include/muduo/base/Logging.h"
#include "../include/muduo/base/Mutex.h"
#include "../include/muduo/net/EventLoop.h"
#include "../include/muduo/net/TcpServer.h"

#include <iostream>
#include <functional>   // bind()
#include <unordered_map>
#include "request.pb.h"

using std::cout;
using std::endl;
using std::string;
using namespace std::placeholders;

class Server
{
public:
    using MessagePtr = std::shared_ptr<google::protobuf::Message>;
    using TranslateRequestPtr = std::shared_ptr<xzt::TranslateRequest>;
    using AddRequestPtr = std::shared_ptr<xzt::AddRequest>;

    Server(int port): 
        _server(
            &_baseloop, 
            muduo::net::InetAddress("0.0.0.0", port), 
            "Server", 
            muduo::net::TcpServer::kReusePort), 
        _dispatcher(
            std::bind(&Server::onUnKnownMessage, 
                    this, 
                    _1, _2, _3)),
        _codec(
            std::bind(&ProtobufDispatcher::onProtobufMessage,
                    &_dispatcher,
                    _1, _2, _3)
        )
    {
        // 注册业务处理回调函数
        _dispatcher.registerMessageCallback<xzt::TranslateRequest>(std::bind(
            &Server::onTranslate, this, 
            _1,  _2, _3
        ));
        _dispatcher.registerMessageCallback<xzt::AddRequest>(std::bind(
            &Server::onAdd, this,
            _1, _2, _3
        ));

        // 将类成员函数设置为服务器的回调处理函数
        _server.setConnectionCallback(
            std::bind(&Server::onConnection, this, _1)
        );
        _server.setMessageCallback(
            std::bind(&ProtobufCodec::onMessage, &_codec, 
            _1, _2, _3
        ));
    }

    void start()
    {
        // 开始事件监听
        _server.start();
        // 开始事件监控，这是死循环阻塞接口
        _baseloop.loop();
    }

private:
    void onUnKnownMessage(const muduo::net::TcpConnectionPtr& conn, const MessagePtr& message, muduo::Timestamp)
    {
        LOG_INFO << "onUnKnownMessage: " << message->GetTypeName();
    }

    void onConnection(const muduo::net::TcpConnectionPtr& conn)
    {
        // 新连接建立成功时的回调函数
        if(conn->connected())
        {
            LOG_INFO << "新连接建立成功!";
        }
        else
        {
            cout << "新连接关闭！";
        }
    }

    void onTranslate(const muduo::net::TcpConnectionPtr& conn, const TranslateRequestPtr& message, muduo::Timestamp)
    {
        // 1.提取message中有效信息
        string req_msg = message->msg();
        // 2.进行信息处理，取得处理后结果
        string rsp_msg = translate(req_msg);
        // 3.组织protobuf的响应
        xzt::TranslateResponse resp;
        resp.set_msg(rsp_msg);
        // 4.发送响应
        _codec.send(conn, resp);
    }

    void onAdd(const muduo::net::TcpConnectionPtr& conn, const AddRequestPtr& message, muduo::Timestamp)
    {
        int num1 = message->num1();
        int num2 = message->num2();

        int result = num1 + num2;

        xzt::AddResponse resp;
        resp.set_result(result);

        _codec.send(conn, resp);
    }

private:
    string translate(const string& msg)
    {   
        static std::unordered_map<string, string> dict_map = {
            {"hello", "你好"},
            {"eat", "吃"},
            {"work", "工作"},
            {"tour", "旅游"},
            {"goodbye", "再见"},
            {"apple", "苹果"},
            {"dog", "狗"},
            {"computer", "计算机"},
            {"friend", "朋友"},
            {"cat", "猫"},
            {"book", "书"},
            {"sun", "太阳"},
            {"moon", "月亮"},
            {"water", "水"},
            {"music", "音乐"},
            {"love", "爱"},
            {"family", "家庭"},
            {"time", "时间"},
            {"happy", "快乐"},
            {"coffee", "咖啡"}
        };

        auto iter = dict_map.find(msg);
        if(iter == dict_map.end())
        {
            return "没听懂你说啥";
        }
        else{
            return iter->second;
        }
    }
private:
    // _baseloop是epoll的事件监控，会进行描述符的事件监控，触发事件后进行io操作
    muduo::net::EventLoop _baseloop;
    // _server用于设置回调函数，告诉服务器收到什么请求该如何处理
    muduo::net::TcpServer _server;
    // 请求分发器对象，要向该对象中注册请求处理函数
    ProtobufDispatcher _dispatcher;
    // protobuf协议处理器，针对收到的请求进行protobuf协议处理
    ProtobufCodec _codec;
};

int main()
{
    Server server(8085);
    server.start();
    return 0;
}